package com.axend.lib_base.help.ble

import android.bluetooth.BluetoothGatt
import android.bluetooth.BluetoothGattCharacteristic
import android.os.Build
import android.os.Handler
import android.os.Looper
import android.util.Log
import cn.com.heaton.blelibrary.ble.Ble
import cn.com.heaton.blelibrary.ble.callback.BleConnectCallback
import cn.com.heaton.blelibrary.ble.callback.BleMtuCallback
import cn.com.heaton.blelibrary.ble.callback.BleNotifyCallback
import cn.com.heaton.blelibrary.ble.callback.BleReadCallback
import cn.com.heaton.blelibrary.ble.callback.BleScanCallback
import cn.com.heaton.blelibrary.ble.callback.BleWriteCallback
import cn.com.heaton.blelibrary.ble.model.BleDevice
import cn.com.heaton.blelibrary.ble.utils.ByteUtils
import com.axend.lib_base.utils.CommUtils
import com.axend.lib_base.utils.log.MyLogUtils
import java.util.UUID

object BleClient {
    private const val TAG = "BleClient"

    private const val BLUETOOTH_NOTIFY_ID = "00002902-0000-1000-8000-00805f9b34fb"

    private val SER_UUID = UUID.fromString("00002760-08c2-11e1-9073-0e8ac72e1001")
    private val SPP_UUID = UUID.fromString("00002760-08c2-11e1-9073-0e8ac72e0001")
    private val INFO_UUID = UUID.fromString("0000180a-0000-1000-8000-00805f9b34fb")
    val BLUETOOTH_FIRMWARE_VERSION_READ_UUID =
        UUID.fromString("00002a26-0000-1000-8000-00805f9b34fb")

    var bleDevice: BleDevice? = null

    private var mOnBleConnectListener: OnBleConnectListener? = null
    private var mOnBleWriteCallback: OnBleWriteCallback? = null
    private var mOnBleReadChaCallback: OnBleReadChaCallback? = null

    interface OnBleConnectListener {
        fun onConnectStatus(device: BleDevice)
    }

    interface OnBleWriteCallback {
        fun onWriteSuccess(device: BleDevice, data: ByteArray)
        fun onWriteFailed(device: BleDevice, errorCode: Int)
    }

    interface OnBleReadChaCallback {
        fun onReadSuccess(uuid: UUID, data: ByteArray)
    }

    init {
        initBle()
    }

    private fun initBle() {
        Ble.options()
            .setLogBleEnable(true)
            .setThrowBleException(true)
            .setLogTAG("AndroidBLE")
            .setAutoConnect(false)
            .setIgnoreRepeat(false)
            .setConnectFailedRetryCount(3)
            .setConnectTimeout(10_000)
            .setScanPeriod(120_000)
            .setMaxConnectNum(7)
            .setUuidService(SER_UUID)
            .setUuidWriteCha(SPP_UUID)
            .setUuidNotifyCha(UUID.fromString(BLUETOOTH_NOTIFY_ID))
            .create<BleDevice>(CommUtils.getContext(), object : Ble.InitCallback {
                override fun success() {
                    MyLogUtils.d(TAG, "success")
                }

                override fun failed(failedCode: Int) {
                    MyLogUtils.d(TAG, "failed:$failedCode")
                }

            })
    }


    /**
     * 开始扫描蓝牙
     */
    fun startScan(callback: BleScanCallback<BleDevice>) {
        Ble.getInstance<BleDevice>().startScan(callback)
    }

    /**
     * 蓝牙开始连接设备
     */
    fun connectDevice(bleDeviceAddress: String) {
        try {
            Ble.getInstance<BleDevice>()
                .connect(bleDeviceAddress, object : BleConnectCallback<BleDevice>() {
                    override fun onConnectionChanged(device: BleDevice?) {
                        /*设备是否连接成功*/
                        device?.let {
                            this@BleClient.bleDevice = device
                            mOnBleConnectListener?.onConnectStatus(it)
                        }
                    }

                    override fun onConnectFailed(device: BleDevice?, errorCode: Int) {
                        super.onConnectFailed(device, errorCode)
                        device?.let {
                            mOnBleConnectListener?.onConnectStatus(it)
                        }
                        Ble.getInstance<BleDevice>().disconnectAll()
//                        MyLogUtils.e("onConnectFailed==errorCode:$errorCode")
                    }

                    override fun onConnectCancel(device: BleDevice?) {
                        super.onConnectCancel(device)
                        device?.let {
                            mOnBleConnectListener?.onConnectStatus(it)
                        }
                        Ble.getInstance<BleDevice>().disconnectAll()
//                        MyLogUtils.e("onConnectCancel:${device?.bleAddress}")
                    }

                    override fun onServicesDiscovered(device: BleDevice?, gatt: BluetoothGatt?) {
                        super.onServicesDiscovered(device, gatt)
//                        gatt?.services?.forEach { service ->
//                            MyLogUtils.d(TAG, "Service UUID: ${service.uuid}")
//                            service.characteristics.forEach { characteristic ->
//                                MyLogUtils.d(TAG, "  Characteristic UUID: ${characteristic.uuid}")
//                                characteristic.descriptors.forEach { descriptor ->
//                                    MyLogUtils.d(TAG, "    Descriptor UUID: ${descriptor.uuid}")
//                                }
//                            }
//                        }

                    }

                    override fun onReady(device: BleDevice?) {
                        super.onReady(device)
                        MyLogUtils.d("onReady Success:${device?.bleAddress}")
                        /*连接成功*/
                        Ble.getInstance<BleDevice>()
                            .enableNotify(device, true, object : BleNotifyCallback<BleDevice>() {
                                override fun onChanged(
                                    device: BleDevice,
                                    characteristic: BluetoothGattCharacteristic
                                ) {
                                    val uuid = characteristic.uuid
                                    val value = characteristic.value
                                    mOnBleWriteCallback?.onWriteSuccess(device, value)
//                                    MyLogUtils.d("onChanged==uuid:$uuid")
                                }

                                override fun onNotifySuccess(device: BleDevice) {
                                    super.onNotifySuccess(device)
//                                    MyLogUtils.d("onNotifySuccess:${device.bleAddress}")
                                    if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
                                        //此处第二个参数  不是特定的   比如你也可以设置500   但是如果设备不支持500个字节则会返回最大支持数
                                        Ble.getInstance<BleDevice>().setMTU(
                                            device.bleAddress,
                                            512,
                                            object : BleMtuCallback<BleDevice?>() {
                                                override fun onMtuChanged(
                                                    device: BleDevice,
                                                    mtu: Int,
                                                    status: Int
                                                ) {
                                                    super.onMtuChanged(device, mtu, status)
//                                                    MyLogUtils.d("onMtuChanged==mtu:$mtu")
                                                }
                                            })
                                    }
                                }

                                override fun onNotifyFailed(device: BleDevice?, failedCode: Int) {
                                    super.onNotifyFailed(device, failedCode)
                                    MyLogUtils.e("onNotifyFailed==failedCode:$failedCode")
                                }


                                override fun onNotifyCanceled(device: BleDevice?) {
                                    super.onNotifyCanceled(device)
                                    MyLogUtils.w("onNotifyCanceled:${device?.bleAddress}")
                                }
                            })

                    }

                })
        } catch (e: Exception) {
            e.printStackTrace()
        }
    }

    /**
     * 蓝牙断开
     */
    fun disconnectDevice() {
        Ble.getInstance<BleDevice>().disconnectAll()
    }

    /**
     *停止蓝牙扫描
     */
    fun stopScan() {
        Ble.getInstance<BleDevice>().stopScan()
    }


    /**
     * 断开连接
     */
    fun closeConnect() {
        try {
            Ble.getInstance<BleDevice>().cancelAutoConnects()
            Ble.getInstance<BleDevice>()
                .cancelConnectings(Ble.getInstance<BleDevice>().connectedDevices)
            Ble.getInstance<BleDevice>().disconnectAll()
            Ble.getInstance<BleDevice>().released()
        } catch (e: Exception) {
            MyLogUtils.w("close<<<bleth<<err")
        }
    }


    fun writeData(data: ByteArray?, onBleWriteCallback: OnBleWriteCallback) {
        MyLogUtils.d(
            "writeData:字节数组大小：${data?.size} ，字节数组内容:${
                ByteUtils.toHexString(
                    data
                )
            }"
        )
        try {
            if (Ble.getInstance<BleDevice?>().connectedDevices[0] == null) {
                return
            }
            this.mOnBleWriteCallback = onBleWriteCallback
            Ble.getInstance<BleDevice>().write(
                Ble.getInstance<BleDevice>().connectedDevices[0],
                data,
                object : BleWriteCallback<BleDevice?>() {
                    override fun onWriteSuccess(
                        device: BleDevice?,
                        characteristic: BluetoothGattCharacteristic
                    ) {
//                        MyLogUtils.d("write data ${ByteUtils.toHexString(data)}")
//                        onBleWriteCallback.onWriteSuccess(device!!, data!!)
                    }

                    override fun onWriteFailed(device: BleDevice?, failedCode: Int) {
                        super.onWriteFailed(device, failedCode)
                        MyLogUtils.d("write data failed $failedCode")
                        onBleWriteCallback.onWriteFailed(device!!, failedCode)
                    }
                })
        } catch (e: java.lang.Exception) {
            MyLogUtils.d("write data failed")
        }
    }

    /**
     * 读取厂家设备信息
     */
    fun readDeviceInformationChaByUUID(uuid: UUID,listener: (uuid: UUID, data: ByteArray) -> Unit) {
        bleDevice?.let {
            Handler(Looper.getMainLooper()).postDelayed({
                Ble.getInstance<BleDevice>().readByUuid(
                    bleDevice, INFO_UUID, uuid,
                    object : BleReadCallback<BleDevice>() {
                        override fun onReadSuccess(
                            device: BleDevice?,
                            characteristic: BluetoothGattCharacteristic?
                        ) {
                            super.onReadSuccess(device, characteristic)
                            MyLogUtils.w("readChaSuccess:${characteristic?.value}")
                            listener.invoke(characteristic?.uuid!!, characteristic?.value!!)
                        }

                        override fun onReadFailed(device: BleDevice?, failedCode: Int) {
                            super.onReadFailed(device, failedCode)
                            MyLogUtils.e("readChaFail:${failedCode}")
                        }
                    }
                )
            }, 1000) // 延迟200毫秒
        }
    }


    /**
     * lambda连接状态回调
     */
    fun setDeviceConnectListener(listener: (BleDevice) -> Unit) {
        this.mOnBleConnectListener = object : OnBleConnectListener {
            override fun onConnectStatus(device: BleDevice) {
                listener.invoke(device)
            }
        }
    }

    /**
     * 特征值读取回调
     */
    fun setOnBleReadChaCallback(listener: (uuid: UUID, data: ByteArray) -> Unit) {
        this.mOnBleReadChaCallback = object : OnBleReadChaCallback {
            override fun onReadSuccess(uuid: UUID, data: ByteArray) {
                listener.invoke(uuid, data)
            }

        }
    }


}